﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace CoD4_Helper.Utils
{
    public class ActiveProfileEventArgs : EventArgs
    {
        public string ProfileName { get; private set; }
        public ActiveProfileEventArgs(string s)
        {
            ProfileName = s;
        }
    }

    static class COD
    {
        #region Constants and variables definitions
        // defaults directories
        const string install_Dir_32 = @"C:\Program Files\Activision\Call of Duty 4 - Modern Warfare";
        const string install_Dir_64 = @"C:\Program Files (x86)\Activision\Call of Duty 4 - Modern Warfare";
        // WIN7 dirs
        const string profiles_Dir_W7_32 = @"VirtualStore\Program Files\Activision\Call of Duty 4 - Modern Warfare\players\profiles";
        const string profile_sDir_W7_64 = @"VirtualStore\Program Files (x86)\Activision\Call of Duty 4 - Modern Warfare\players\profiles";
        // XP dirs or WIN7 with UAC disabled
        const string profiles_Dir_XP_32 = @"C:\Program Files\Activision\Call of Duty 4 - Modern Warfare\players\profiles";
        const string profiles_Dir_XP_64 = @"C:\Program Files (x86)\Activision\Call of Duty 4 - Modern Warfare\players\profiles";
        #endregion

        /// <summary>
        /// The directory where profiles are stored
        /// </summary>
        public static string ProfilesDir { get; set; }

        /// <summary>
        /// The directory of the game
        /// </summary>
        public static string InstallationDir { get; set; }

        //private static string activeProfile;
        /// <summary>
        /// Store the current active profile (active.txt)
        /// </summary>
        public static string ActiveProfile
        {
            get { return GetActiveProfile(); }
            set
            {
                SetActiveProfile(value);
                OnActiveProfileChange(value);
            }
        }

        public delegate void ActiveProfileEventHandler(object sender, ActiveProfileEventArgs e);
        // http://stackoverflow.com/questions/289002/how-to-raise-custom-event-from-a-static-class
        // No race condition here
        public static event ActiveProfileEventHandler ActiveProfileChanged = delegate { };

        private static void OnActiveProfileChange(string profile)
        {
            // the null-check is not necessary, it's always not null
            ActiveProfileChanged(null, new ActiveProfileEventArgs(profile));
        }


        /// <summary>
        /// Set InstallationDir and ProfilesDir to their correct value
        /// </summary>
        public static void InizializePaths()
        {
            // Set deafault directories
            SetDefCodDirs();

            string cstmInstDir = Utils.SettingsManager.GetCustomInstDir();
            string cstmProfDir = Utils.SettingsManager.GetCustomProfDir();

            if (Utils.SettingsManager.HasCustomInstDir && Utils.COD.DetectCODInstallation(cstmInstDir))
                InstallationDir = Utils.SettingsManager.GetCustomInstDir();

            if (Utils.SettingsManager.HasCustomProfDir && Utils.COD.DetectCODProfiles(cstmProfDir))
                ProfilesDir = Utils.SettingsManager.GetCustomProfDir();
        }

        /// <summary>
        /// Sets the Default Installation and Profiles directories of CoD
        /// </summary>
        public static void SetDefCodDirs()
        {
            #region Old method
            // detect os version and architecture
            //OSUtils.DetectOS();
            
            // set the right directory according to the current OS
            //switch (OSUtils.OsVers)
            //{
            //    case OSVersions.WinXP:
            //        if (OSUtils.OsArch == OSArchitecture.x86)
            //        {
            //            InstallationDir = install_Dir_32;
            //            ProfilesDir = profiles_Dir_XP_32;
            //        }
            //        else
            //        {
            //            InstallationDir = install_Dir_64;
            //            ProfilesDir = profiles_Dir_XP_64;
            //        }
            //        break;

            //    case OSVersions.WinVista:
            //        if (OSUtils.OsArch == OSArchitecture.x86)
            //        {
            //            InstallationDir = install_Dir_32;

            //            if (Directory.Exists(Path.Combine(OSUtils.AppDataDir, profiles_Dir_W7_32)))
            //                ProfilesDir = Path.Combine(OSUtils.AppDataDir, profiles_Dir_W7_32);
            //            else
            //                ProfilesDir = profiles_Dir_XP_32;
            //        }
            //        else
            //        {
            //            InstallationDir = install_Dir_64;

            //            if (Directory.Exists(Path.Combine(OSUtils.AppDataDir, profile_sDir_W7_64)))
            //                ProfilesDir = Path.Combine(OSUtils.AppDataDir, profile_sDir_W7_64);
            //            else
            //                ProfilesDir = profiles_Dir_XP_64;
            //        }
            //        break;

            //    case OSVersions.Win7:
            //        if (OSUtils.OsArch == OSArchitecture.x86)
            //        {
            //            InstallationDir = install_Dir_32;

            //            if (Directory.Exists(Path.Combine(OSUtils.AppDataDir, profiles_Dir_W7_32)))
            //                ProfilesDir = Path.Combine(OSUtils.AppDataDir, profiles_Dir_W7_32);
            //            else
            //                ProfilesDir = profiles_Dir_XP_32;
            //        }
            //        else
            //        {
            //            InstallationDir = install_Dir_64;

            //            if (Directory.Exists(Path.Combine(OSUtils.AppDataDir, profile_sDir_W7_64)))
            //                ProfilesDir = Path.Combine(OSUtils.AppDataDir, profile_sDir_W7_64);
            //            else
            //                ProfilesDir = profiles_Dir_XP_64;
            //        }
            //        break;
            //} 
            #endregion
            InstallationDir = GetDefaultInstDir();
            ProfilesDir = GetDefaultProfDir();
            
        }

        /// <summary>
        /// Retrieves the directory containing the installation of CoD 
        /// </summary>
        public static string GetDefaultInstDir()
        {
            // set the right directory according to the current OS
            switch (OSUtils.OsVers)
            {
                case OSVersions.WinXP:
                case OSVersions.WinVista:
                case OSVersions.Win7:
                    if (OSUtils.OsArch == OSArchitecture.x86)
                        return install_Dir_32;
                    else
                        return install_Dir_64;
            }

            return null;
        }

        /// <summary>
        /// Retrieves the directory containing the user's game profiles
        /// </summary>
        public static string GetDefaultProfDir()
        {
            // set the right directory according to the current OS
            switch (OSUtils.OsVers)
            {
                case OSVersions.WinXP:
                    if (OSUtils.OsArch == OSArchitecture.x86)
                        return profiles_Dir_XP_32;
                    else
                        return profiles_Dir_XP_64;

                case OSVersions.WinVista:
                    if (OSUtils.OsArch == OSArchitecture.x86)
                    {
                        if (Directory.Exists(Path.Combine(OSUtils.AppDataDir, profiles_Dir_W7_32)))
                            return Path.Combine(OSUtils.AppDataDir, profiles_Dir_W7_32);
                        else
                            return profiles_Dir_XP_32;
                    }
                    else
                    {
                        if (Directory.Exists(Path.Combine(OSUtils.AppDataDir, profile_sDir_W7_64)))
                            return Path.Combine(OSUtils.AppDataDir, profile_sDir_W7_64);
                        else
                            return profiles_Dir_XP_64;
                    }

                case OSVersions.Win7:
                    if (OSUtils.OsArch == OSArchitecture.x86)
                    {
                        if (Directory.Exists(Path.Combine(OSUtils.AppDataDir, profiles_Dir_W7_32)))
                            return Path.Combine(OSUtils.AppDataDir, profiles_Dir_W7_32);
                        else
                            return profiles_Dir_XP_32;
                    }
                    else
                    {
                        if (Directory.Exists(Path.Combine(OSUtils.AppDataDir, profile_sDir_W7_64)))
                            return Path.Combine(OSUtils.AppDataDir, profile_sDir_W7_64);
                        else
                            return profiles_Dir_XP_64;
                    }
            }

            return null;
        }
        
        #region Installation and Profiles detectors
        /// <summary>
        /// Detects whether COD4 is installed or not
        /// (it's referred to the current instance)
        /// </summary>
        public static bool DetectCODInstallation()
        {
            string iw3mp = Path.Combine(InstallationDir, "iw3mp.exe");

            if (File.Exists(iw3mp))
                return true;
            else
                return false;
        }

        /// <summary>
        /// Detects whether COD4 is installed or not
        /// </summary>
        /// <param name="instDir">The directory to check</param>
        public static bool DetectCODInstallation(string instDir)
        {
            string iw3mp = Path.Combine(instDir, "iw3mp.exe");

            if (File.Exists(iw3mp))
                return true;
            else
                return false;
        }

        /// <summary>
        /// Detects if the path to the user Profiles is correct
        /// </summary>
        /// <returns>Whether is correct or not</returns>
        public static bool DetectCODProfiles()
        {
            if (Directory.Exists(ProfilesDir))
            {
                DirectoryInfo[] dirs = new DirectoryInfo(ProfilesDir).GetDirectories();
                if ((dirs.Length > 0) && File.Exists(Path.Combine(ProfilesDir, "active.txt")))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// Detects if the path to the user Profiles is correct
        /// </summary>
        /// <param name="profDir">The directory of the profiles to check</param>
        public static bool DetectCODProfiles(string profDir)
        {
            if (Directory.Exists(profDir))
            {
                DirectoryInfo[] dirs = new DirectoryInfo(profDir).GetDirectories();
                if ((dirs.Length > 0) && File.Exists(Path.Combine(profDir, "active.txt")))
                    return true;
            }
            return false;
        } 
        #endregion

        #region CoD Launcher
        /// <summary>
        /// Start Call of Duty 4
        /// </summary>
        public static void LaunchCoD()
        {
            // create new process
            Process cod4 = new Process();
            // set the excutable path
            cod4.StartInfo.FileName = Path.Combine(InstallationDir, "iw3mp.exe");
            // set a working directory to prevent startup error
            cod4.StartInfo.WorkingDirectory = InstallationDir;
            // enable Exited Event
            cod4.EnableRaisingEvents = true;
            cod4.Exited += new EventHandler(cod4_Exited);
            // start cod4 mp
            cod4.Start();
        }

        /// <summary>
        /// Start Call of Duty 4 with arguments
        /// </summary>
        /// <param name="args">Command-line arguments</param>
        public static void LaunchCoD(string args)
        {
            Process cod4 = new Process();
            cod4.EnableRaisingEvents = true;
            cod4.Exited += new EventHandler(cod4_Exited);
            cod4.StartInfo.FileName = Path.Combine(InstallationDir, "iw3mp.exe");
            cod4.StartInfo.WorkingDirectory = InstallationDir;
            // set args
            cod4.StartInfo.Arguments = args;

            cod4.Start();
        }

        /// <summary>
        /// Start Call of Duty 4 with selected mod
        /// </summary>
        /// <param name="modName">The Mod name</param>
        public static void LaunchCoDMod(string modName)
        {
            Process cod4 = new Process();
            //cod4.StartInfo.FileName = Path.Combine(InstallationDir, "iw3mp.exe") + " +set fs_game \"mods/" + modName + "\"";
            cod4.EnableRaisingEvents = true;
            cod4.Exited += new EventHandler(cod4_Exited);
            cod4.StartInfo.FileName = Path.Combine(InstallationDir, "iw3mp.exe");
            cod4.StartInfo.Arguments = "+set fs_game \"mods/" + modName + "\"";
            cod4.StartInfo.WorkingDirectory = InstallationDir;
            if (!string.IsNullOrWhiteSpace(modName))
            {
                cod4.Start();
            }

        }

        // Event fired when CoD is closed
        static void cod4_Exited(object sender, EventArgs e)
        {
            //System.Windows.Forms.MessageBox.Show("COD exited");
        }
        #endregion
        
        #region Profiles stuff
        /// <summary>
        /// Gets all user profiles
        /// </summary>
        /// <returns>A list of players name</returns>
        public static List<string> GetProfiles()
        {
            if (Directory.Exists(ProfilesDir))
            {
                DirectoryInfo dirInfo = new DirectoryInfo(ProfilesDir);

                DirectoryInfo[] dirs = dirInfo.GetDirectories();

                if (dirs.Length != 0)
                {
                    List<string> players = new List<string>();

                    foreach (var folders in dirs)
                    {
                        players.Add(folders.Name);
                    }

                    return players;
                }
            }

            return null;
        }

        /// <summary>
        /// Reads the active.txt file to get the active profile
        /// </summary>
        /// <returns>The active profile name</returns>
        private static string GetActiveProfile()
        {
            string file = Path.Combine(ProfilesDir, "active.txt");

            if (File.Exists(file))
            {
                using (StreamReader sr = new StreamReader(file))
                {
                    return sr.ReadLine();
                }
            }
            return null;
        }

        /// <summary>
        /// Set the active profile in the active.txt file 
        /// </summary>
        /// <param name="activeProfileName">The name of the profile to make activ</param>
        private static void SetActiveProfile(string activeProfileName)
        {
            string file = Path.Combine(ProfilesDir, "active.txt");

            if (File.Exists(file))
            {
                using (StreamWriter sw = new StreamWriter(file))
                {
                    sw.Write(activeProfileName);
                }
            }
        }
        #endregion

        /// <summary>
        /// Gets all the mods installed
        /// </summary>
        /// <returns>A list of mods' name</returns>
        public static List<string> GetMods()
        {
            string pathMods = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(ProfilesDir)), "Mods");

            if (Directory.Exists(pathMods))
            {
                DirectoryInfo dirInfo = new DirectoryInfo(pathMods);
                DirectoryInfo[] dirs = dirInfo.GetDirectories();

                if (dirs.Length != 0)
                {
                    List<string> mods = new List<string>();

                    mods.Add("None");

                    foreach (var folders in dirs)
                    {
                        mods.Add(folders.Name);
                    }

                    return mods;
                }
            }

            return null;
        }

    }
}
